package fr.univ.context.process;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.List;
import java.util.Locale;

import fr.univ.context.data.entity.*;
import fr.univ.context.data.handler.DataBaseHandler;
import fr.univ.context.data.info.*;
import fr.univ.context.data.table.*;
import fr.univ.context.utilities.BackupDB;
import fr.univ.context.utilities.Preferences;

import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.location.LocationProvider;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.util.Log;
import android.widget.Toast;

public class ServiceContext extends Service implements Runnable {
	
	private int TIME_SLEEP;
	
	private DataBaseHandler<NetworkTable> dNetwork;
	private DataBaseHandler<MemoryTable> dMemory;
	private DataBaseHandler<RunningApplicationTable> dApplication; 
	private DataBaseHandler<PositionTable> dPosition;
	private static DataBaseHandler<FocusApplicationTable> dFocusApp;
	
	private Preferences preferences;
	private GPSListener gpsListener;
	private LocationManager locationManager;
	private int idCapture;
	private static String date;
	
	private static String appName;
	private static String processName;
	
	private static Object systemService;
	
	private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
        	Intent i = new Intent(ServiceContext.this, DialogActivity.class);
        	i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        	startActivity(i);       
        }
    };

	@Override
	public void onCreate(){ 
		
		preferences = new Preferences(this);
		idCapture = 0;
		
		systemService = getSystemService(ACTIVITY_SERVICE);
		
		dNetwork = new DataBaseHandler<NetworkTable>(new NetworkTable(this));
		dMemory = new DataBaseHandler<MemoryTable>(new MemoryTable(this));
		dApplication = new DataBaseHandler<RunningApplicationTable>(new RunningApplicationTable(this));
		dFocusApp = new DataBaseHandler<FocusApplicationTable>(new FocusApplicationTable(this));
		dPosition = new DataBaseHandler<PositionTable>(new PositionTable(this));

		gpsListener = new GPSListener();
		locationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
		
		TIME_SLEEP = preferences.loadTimeSleep();
		
		locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, TIME_SLEEP * 60000, 0, gpsListener);
	}
	
	@Override
	public void onStart(Intent intent, int startId){	
		
		if ( idCapture++ > 0 ){
			new Thread(this).start();
		}
	}
	
	@Override
	public void onDestroy(){
		Log.i("Exec", "SERVICE STOPPED !!!");
		BackupDB.writeToSD(this);
		locationManager.removeUpdates(gpsListener); //Remove the locationlistener
	}
	
	@Override
	public void run() {
				
		date = getDate();
		
		//-----------MEMORY-------------------------------
		
		String avInternalMemorySize = MemorySize.formatSize(MemorySize.getAvailableInternalMemorySize());
		String avExternalMemorySize = MemorySize.formatSize(MemorySize.getAvailableExternalMemorySize());
		String avRamMenory = MemorySize.formatSize( MemorySize.getAvailableMemoryRAM(this));
		
		avExternalMemorySize = MemorySize.getAvailableExternalMemorySize() == -1 ? null : avExternalMemorySize;
		
		dMemory.insert( new Memory(avInternalMemorySize, avExternalMemorySize, avRamMenory, date ) );
		
		//-----------NETWORK-------------------------------
		
		Connectivity inStatus = new Connectivity(this);
		dNetwork.insert( new Network(inStatus.getType(), inStatus.getSSID(), date ) );
		
		//-----------RUNNING APPLICATIONS------------------
		
		InfoRunningApplications irApps = new InfoRunningApplications(this);
		
		Hashtable<String, String> apps = irApps.getListNameAppRunning();
		Enumeration<String> keys = apps.keys();
		
		while (keys.hasMoreElements()) {
			String key = keys.nextElement();
			
			RunningApplication ap = new RunningApplication(key, apps.get(key), date );
			dApplication.insert(ap);
		}
		
		//------------FOCUS APPLICATION---------------------
		
		ActivityManager activityManager = (ActivityManager) systemService;
		List<ActivityManager.RunningTaskInfo> appProcesses = activityManager.getRunningTasks(1);
		PackageManager pm = getPackageManager();
		
		CharSequence c = null;
		
		try {
			c = pm.getApplicationLabel(pm.getApplicationInfo(appProcesses.get(0).topActivity.getPackageName(),
					PackageManager.GET_META_DATA));
			
			appName = c.toString();
			processName = appProcesses.get(0).topActivity.getPackageName();
			
		} catch (NameNotFoundException e) {
			e.printStackTrace();
		}
		
		boolean flag = preferences.loadFlagDialog();

		if (flag){
			handler.sendMessage(new Message());	
		} else {
			teste(null);
		}
		
		//-------------BACKUP DATA BASE-----------------------------------------
		BackupDB.writeToSD(this);
	}
	
	public static void teste (String description) {
		
		FocusApplication fa = new FocusApplication( appName, processName, description , date);	
		dFocusApp.insert(fa);
	}
	
	@Override
	public IBinder onBind(Intent arg0) {
		return null;
	}
	
	@SuppressLint("SimpleDateFormat")
	public static String getDate(){
		
		SimpleDateFormat simpleFormat = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
		return simpleFormat.format( new Date( System.currentTimeMillis() ));
	}
	
	private final class GPSListener implements LocationListener {

		@Override
		public void onLocationChanged(Location location) {
			
			double lat = location.getLatitude();
		    double lng = location.getLongitude();
		    String address = null;
		    
		    Geocoder geocoder = new Geocoder(ServiceContext.this, Locale.FRANCE);
			
			try {
				List<Address> addresses = geocoder.getFromLocation(lat, lng, 1);
				 
				if(addresses != null) {
					Address returnedAddress = addresses.get(0);
					StringBuilder strReturnedAddress = new StringBuilder("Address:\n");
						
					for(int i = 0; i < returnedAddress.getMaxAddressLineIndex(); i++) {
						strReturnedAddress.append(returnedAddress.getAddressLine(i)).append("\n");
					}
					address = strReturnedAddress.toString();
				}else{
					address = "No Address returned!";
				}		 
			} catch(IOException e) {
			 	e.printStackTrace();
			 	address = "Can't find address !";
			}

			dPosition.insert(new Position(lat, lng, address, getDate() ));
		}
	
		@Override
		public void onProviderDisabled(String provider) {
			Toast.makeText(ServiceContext.this, "Disabled provider: " + provider,
			        Toast.LENGTH_SHORT).show();		
		}
	
		@Override
		public void onProviderEnabled(String provider) {
			Toast.makeText(ServiceContext.this, "Enabled new provider: " + provider,
			        Toast.LENGTH_SHORT).show();			
		}
		
		@Override
		public void onStatusChanged(String provider, int status, Bundle extras) {
			
			//This is called when the GPS status alters 
			switch (status) {
				case LocationProvider.OUT_OF_SERVICE:
					Log.i("Teste", "Status Changed: Out of Service");
					break;
				case LocationProvider.TEMPORARILY_UNAVAILABLE:
					Log.i("Teste", "Status Changed: Temporarily Unavailable");
					break;
				case LocationProvider.AVAILABLE:
					Log.i("Teste", "Status Changed: Available");
					break;
			}	
		}
	}
}